package com.jl15988.chainlog.service.impl;

import com.jl15988.chainlog.model.ChainApiLog;
import com.jl15988.chainlog.model.ChainMethodLog;
import com.jl15988.chainlog.model.ChainTraceTree;
import com.jl15988.chainlog.service.ChainTraceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;

/**
 * 基于内存的链式跟踪服务实现
 * 适用于单机部署，数据存储在内存中
 */
@Service
@Slf4j
public class MemoryChainTraceService implements ChainTraceService {

    /**
     * API日志存储 - 按时间顺序
     */
    private final Queue<ChainApiLog> apiLogs = new ConcurrentLinkedQueue<>();

    /**
     * 方法日志存储 - 按时间顺序
     */
    private final Queue<ChainMethodLog> methodLogs = new ConcurrentLinkedQueue<>();

    /**
     * API日志索引 - 快速查找
     */
    private final Map<String, ChainApiLog> apiLogIndex = new ConcurrentHashMap<>();

    /**
     * 方法日志索引 - 快速查找方法日志
     */
    private final Map<String, ChainMethodLog> methodLogIndex = new ConcurrentHashMap<>();

    /**
     * 调用链根节点映射 - 记录每个调用链的根节点ID
     */
    private final Map<String, String> chainRootMapping = new ConcurrentHashMap<>();

    /**
     * 子节点映射 - 记录每个节点的直接子节点
     */
    private final Map<String, List<String>> childrenMapping = new ConcurrentHashMap<>();

    /**
     * 最大存储数量
     */
    private static final int MAX_API_LOGS = 1000;
    private static final int MAX_METHOD_LOGS_PER_API = 500;

    @Override
    public void saveApiLog(ChainApiLog apiLog) {
        if (apiLog == null || apiLog.getId() == null) {
            return;
        }

        // 添加到队列和索引
        apiLogs.offer(apiLog);
        apiLogIndex.put(apiLog.getId(), apiLog);

        // API作为调用链的根节点
        chainRootMapping.put(apiLog.getId(), apiLog.getId());

        // 清理过期数据
        while (apiLogs.size() > MAX_API_LOGS) {
            ChainApiLog removed = apiLogs.poll();
            if (removed != null) {
                cleanupNodeData(removed.getId());
            }
        }

        log.debug("Saved API log: {}", apiLog.getId());
    }

    @Override
    public void saveMethodLog(ChainMethodLog methodLog) {
        if (methodLog == null || methodLog.getId() == null) {
            return;
        }

        // 添加到队列和索引
        methodLogs.offer(methodLog);
        methodLogIndex.put(methodLog.getId(), methodLog);

        // 处理调用链关系
        String parentId = methodLog.getParentId();
        if (parentId != null) {
            // 有父节点，建立父子关系
            childrenMapping.computeIfAbsent(parentId, k -> new ArrayList<>()).add(methodLog.getId());

            // 继承父节点的根节点
            String rootId = findRootId(parentId);
            if (rootId != null) {
                chainRootMapping.put(methodLog.getId(), rootId);
            }
        } else {
            // 没有父节点，作为独立调用链的根节点
            chainRootMapping.put(methodLog.getId(), methodLog.getId());
        }

        // 清理过期数据
        while (methodLogs.size() > MAX_METHOD_LOGS_PER_API * 10) { // 总体限制
            ChainMethodLog removed = methodLogs.poll();
            if (removed != null) {
                cleanupNodeData(removed.getId());
            }
        }

        log.debug("Saved method log: {} with parent: {}", methodLog.getId(), parentId);
    }

    /**
     * 查找调用链的根节点ID
     */
    private String findRootId(String nodeId) {
        return chainRootMapping.get(nodeId);
    }

    /**
     * 清理节点相关的所有数据
     */
    private void cleanupNodeData(String nodeId) {
        // 移除各种映射
        chainRootMapping.remove(nodeId);
        childrenMapping.remove(nodeId);

        // 从父节点的子节点列表中移除
        for (List<String> children : childrenMapping.values()) {
            children.remove(nodeId);
        }

        // 移除索引
        apiLogIndex.remove(nodeId);
        methodLogIndex.remove(nodeId);
    }

    @Override
    public ChainTraceTree getTraceTree(String rootId) {
        // 先尝试作为API日志查找
        ChainApiLog apiLog = apiLogIndex.get(rootId);
        if (apiLog != null) {
            return buildTreeFromRoot(rootId, buildApiNode(apiLog));
        }

        // 再尝试作为方法日志查找
        ChainMethodLog methodLog = methodLogIndex.get(rootId);
        if (methodLog != null) {
            // 检查是否是根节点
            String actualRootId = findRootId(rootId);
            if (actualRootId != null && actualRootId.equals(rootId)) {
                return buildTreeFromRoot(rootId, buildMethodNode(methodLog));
            }
        }

        return null;
    }

    /**
     * 构建API节点
     */
    private ChainTraceTree buildApiNode(ChainApiLog apiLog) {
        ChainTraceTree node = new ChainTraceTree();
        node.setId(apiLog.getId());
        node.setType("api");
        node.setName(apiLog.getOperationName() != null ? apiLog.getOperationName() : "API");
        node.setDescription(apiLog.getDesc());
        node.setMethod(apiLog.getMethod());
        node.setClassName(apiLog.getClassName());
        node.setStartTime(apiLog.getStartTime());
        node.setEndTime(apiLog.getEndTime());
        node.setDuration(apiLog.getDuration());
        node.setLevel(0);
        node.setSuccess(apiLog.isSuccess());
        node.setExceptionInfo(apiLog.getExceptionInfo());
        node.setParams(apiLog.getParams());
        node.setResult(apiLog.getResult());
        node.setCustoms(apiLog.getCustoms());

        // API特有字段
        node.setUrl(apiLog.getUrl());
        node.setHttpMethod(apiLog.getHttpMethod());
        node.setClientIp(apiLog.getClientIp());
        node.setModule(apiLog.getModule());
        node.setOperationType(apiLog.getOperationType());
        node.setHeaders(apiLog.getHeaders());

        return node;
    }

    /**
     * 构建方法节点
     */
    private ChainTraceTree buildMethodNode(ChainMethodLog methodLog) {
        ChainTraceTree node = new ChainTraceTree();
        node.setId(methodLog.getId());
        node.setParentId(methodLog.getParentId());
        node.setType("method");
        node.setName(methodLog.getName() != null ? methodLog.getName() : "Method");
        node.setDescription(methodLog.getDesc());
        node.setMethod(methodLog.getMethod());
        node.setClassName(methodLog.getClassName());
        node.setStartTime(methodLog.getStartTime());
        node.setEndTime(methodLog.getEndTime());
        node.setDuration(methodLog.getDuration());
        node.setLevel(methodLog.getLevel());
        node.setSuccess(methodLog.isSuccess());
        node.setExceptionInfo(methodLog.getExceptionInfo());
        node.setParams(methodLog.getParams());
        node.setResult(methodLog.getResult());
        node.setCustoms(methodLog.getCustoms());

        return node;
    }

    /**
     * 从根节点构建完整的调用树
     */
    private ChainTraceTree buildTreeFromRoot(String rootId, ChainTraceTree rootNode) {
        Map<String, ChainTraceTree> nodeMap = new HashMap<>();
        nodeMap.put(rootId, rootNode);

        // 递归构建子树
        buildChildrenRecursively(rootId, rootNode, nodeMap);

        // 对所有节点的子节点按开始时间排序
        sortChildrenByStartTime(rootNode);

        return rootNode;
    }

    /**
     * 递归构建子节点
     */
    private void buildChildrenRecursively(String parentId, ChainTraceTree parentNode, Map<String, ChainTraceTree> nodeMap) {
        List<String> childrenIds = childrenMapping.get(parentId);
        if (childrenIds == null || childrenIds.isEmpty()) {
            return;
        }

        for (String childId : childrenIds) {
            ChainMethodLog childMethodLog = methodLogIndex.get(childId);
            if (childMethodLog != null) {
                ChainTraceTree childNode = buildMethodNode(childMethodLog);
                parentNode.getChildren().add(childNode);
                nodeMap.put(childId, childNode);

                // 递归构建子节点的子节点
                buildChildrenRecursively(childId, childNode, nodeMap);
            }
        }
    }

    /**
     * 递归排序子节点
     */
    private void sortChildrenByStartTime(ChainTraceTree node) {
        if (node.getChildren() != null && !node.getChildren().isEmpty()) {
            node.getChildren().sort(Comparator.comparing(ChainTraceTree::getStartTime));
            node.getChildren().forEach(this::sortChildrenByStartTime);
        }
    }

    @Override
    public List<ChainApiLog> getRecentApiLogs(int limit) {
        return apiLogs.stream()
                .sorted((a, b) -> b.getStartTime().compareTo(a.getStartTime()))
                .limit(limit)
                .collect(Collectors.toList());
    }

    /**
     * 获取最近的调用链（包括独立的方法调用链）
     */
    @Override
    public List<Object> getRecentChains(int limit) {
        List<Object> allChains = new ArrayList<>();

        // 添加API调用链
        allChains.addAll(apiLogs);

        // 添加独立的方法调用链（根节点）
        for (ChainMethodLog methodLog : methodLogs) {
            String rootId = findRootId(methodLog.getId());
            if (rootId != null && rootId.equals(methodLog.getId()) && methodLog.getParentId() == null) {
                allChains.add(methodLog);
            }
        }

        // 按时间排序
        allChains.sort((a, b) -> {
            Date timeA = (a instanceof ChainApiLog) ? ((ChainApiLog) a).getStartTime() : ((ChainMethodLog) a).getStartTime();
            Date timeB = (b instanceof ChainApiLog) ? ((ChainApiLog) b).getStartTime() : ((ChainMethodLog) b).getStartTime();
            return timeB.compareTo(timeA);
        });

        return allChains.stream().limit(limit).collect(Collectors.toList());
    }

    @Override
    public List<ChainApiLog> searchApiLogs(String url, String method, String module,
                                           Long startTime, Long endTime, int page, int size) {
        return apiLogs.stream()
                .filter(log -> url == null || log.getUrl().contains(url))
                .filter(log -> method == null || method.equals(log.getHttpMethod()))
                .filter(log -> module == null || module.equals(log.getModule()))
                .filter(log -> startTime == null || log.getStartTime().getTime() >= startTime)
                .filter(log -> endTime == null || log.getStartTime().getTime() <= endTime)
                .sorted((a, b) -> b.getStartTime().compareTo(a.getStartTime()))
                .skip((long) page * size)
                .limit(size)
                .collect(Collectors.toList());
    }

    @Override
    public void cleanExpiredData(long expireTime) {
        long currentTime = System.currentTimeMillis();

        // 清理过期的API日志
        Iterator<ChainApiLog> apiIterator = apiLogs.iterator();
        while (apiIterator.hasNext()) {
            ChainApiLog apiLog = apiIterator.next();
            if (currentTime - apiLog.getStartTime().getTime() > expireTime) {
                apiIterator.remove();
                cleanupNodeData(apiLog.getId());
            }
        }

        // 清理过期的方法日志
        Iterator<ChainMethodLog> methodIterator = methodLogs.iterator();
        while (methodIterator.hasNext()) {
            ChainMethodLog methodLog = methodIterator.next();
            if (currentTime - methodLog.getStartTime().getTime() > expireTime) {
                methodIterator.remove();
                cleanupNodeData(methodLog.getId());
            }
        }

        log.info("Cleaned expired data, remaining API logs: {}, method logs: {}",
                apiLogs.size(), methodLogs.size());
    }
}